#include "glConsole.h"

void glConsole::log()
{
	ofstream l_file;
	l_file.open(Engine::consoleSettings.logFile.c_str());

	if (l_file.is_open() && num_lines > 1)
	{
		for (int i = 0; i < num_lines - 1; i++)
			l_file << lines[i] + "\n";

		l_file.close();
		print("Log saved to %s", Engine::consoleSettings.logFile.c_str());
	}
	else
		print("Error: console is empty!");

}

void glConsole::load_com(const char *file_name)
{
	ifstream c_file;
	string line;

	c_file.open(file_name);

	if (c_file.is_open())
	{
		while (!c_file.eof())
		{
			c_file >> line;
			commands.push_back(line);
		}
	}

	c_file.close();

}

void glConsole::clear_lines()
{
	cur = 0;
	cur_pos = 0;
	max_cur_pos = 0;
	c_pos = 0;

	num_lines = 0; // nulovy pocet zaznamu
	command_line = "";

	lines.clear();

	Lock = SDL_CreateSemaphore(1);
}

glConsole::glConsole()
{
	load_com(
			(Engine::consoleSettings.consolePath + Engine::consoleSettings.commandFile).c_str());

	clear_lines();

	// load backgroud texture
	std::string path;

	path = Engine::fileStructure.texturePath
			+ Engine::consoleSettings.consolePath;

	textures = new TexPool(path.c_str());
  textures->loadDir();

	// load font
	font = new glFont(Engine::consoleSettings.consoleFont);
	font->BuildFont(); // vytvoreni fontu

	background = glGenLists(1);

	glNewList(background, GL_COMPILE); // Start Building A List

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,
			textures->getTexIdByName(Engine::consoleSettings.consoleBackground)); // Select Our Font Texture
	glColor4f(1.0f, 1.0f, 1.0f, 0.7);
	glBegin(GL_QUADS);

	glTexCoord2i(0, 0);
	glVertex2i(0, 0);
	glTexCoord2i(Engine::screenSettings.screenWidth, 0);
	glVertex2i(Engine::screenSettings.screenWidth, 0);
	glTexCoord2i(Engine::screenSettings.screenWidth,
			Engine::screenSettings.screenHeight);
	glVertex2i(Engine::screenSettings.screenWidth,
			Engine::screenSettings.screenHeight);
	glTexCoord2i(0, Engine::screenSettings.screenHeight);
	glVertex2i(0, Engine::screenSettings.screenHeight);
	glEnd();
	glDisable(GL_TEXTURE_2D);
	glEndList();

	glColor4f(1.0f, 1.0f, 1.0f, 1.0);
	//ctor
}

void glConsole::print(const char *fmt, ...)
{
	//###########################################################
	// CRITICAL SECTION !!!
	SDL_SemWait(Lock);

	char text[256];
	va_list ap;

	va_start(ap, fmt);
	// Parses The String For Variables
	vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
	va_end(ap);

	lines.push_back(text);
	num_lines++;
	SDL_SemPost(Lock);
	//###########################################################
}

int glConsole::command(string com)
{
	char *cstr;

	// obsluha internich prikazu
	lines.push_back(com);

	num_lines++;

	int c = -2; // cislo prikazu

	if (com.compare("") == 0)
		c = C_NEW_LINE;

	if (com.compare("clrscr") == 0)
	{
		clear_lines();
		c = C_CLEAR;
	}

	if (com.compare("help") == 0)
	{
		print("=========================================");
		print("Help for console:");
		print("ID   command         Description");
		print("-----------------------------------------");
		print("0    clrscr          clear screen");
		print("1    help            help for application");
		print("2    exit            close application");
		print("3    log             save console to file");
		print("");
		print("Extern commands:");

		for (unsigned int i = 0; i < commands.size(); i++)
		{
			cstr = new char[commands[i].size() + 1];
			strcpy(cstr, commands[i].c_str());

			print("%i    %s", i + 4, cstr);

			delete[] cstr;
		}

		print("");

		c = C_HELP;
	}

	if (com.compare("exit") == 0)
		c = C_EXIT;

	if (com.compare("log") == 0)
	{
		c = C_LOG;
		log();
	}

	for (unsigned int i = 0; i < commands.size(); i++) // obsluha externich prikazu
	{
		if (com.compare(commands[i]) == 0)
		{
			c = i + 4;
		}

	}

	if (c == -2)
		print("Error: unknown command!");

	return c;
}

void glConsole::show_lines()
{
	char * cstr;

	for (int a = 0; a < (Engine::screenSettings.screenHeight / 16); a++)
	{
		font->glPrint(0, 16 * a, 0, ">>");
	}

	for (int i = 0; i < num_lines; i++)
	{
		cstr = new char[lines[i].size() + 1];
		strcpy(cstr, lines[i].c_str());

		font->glPrint(35,
				(((Engine::screenSettings.screenHeight - 16) - (16 * num_lines))
						+ 16 * i), 0, cstr); // vypisuje zaznamy do fronty

		delete[] cstr;
	}

	cstr = new char[command_line.size() + 1];
	strcpy(cstr, command_line.c_str());
	font->glPrint(35, Engine::screenSettings.screenHeight - 16, 0, cstr);

	delete[] cstr;

}

void glConsole::show_cursor()
{
	cur += 1;

	if (cur < 25)
	{
		font->glPrint(35 + (13 * cur_pos), Engine::screenSettings.screenHeight - 16,
				0, "_");
	}
	else
	{
		font->glPrint(35 + (13 * cur_pos), Engine::screenSettings.screenHeight - 16,
				0, " ");
	}

	if (cur == 50)
		cur = 0;
}

int glConsole::get_line(SDL_Event key_pressed)
{
	int r = 0; // navratova hodnata, pomocna promenna

	if (key_pressed.type == SDL_KEYDOWN) // vyhodnoceni stiskle klavesy
	{

		switch (key_pressed.key.keysym.sym)
		{
		case SDLK_UP:
			c_pos += 1;

			break;

		case SDLK_DOWN:
			c_pos -= 1;
			break;

		case SDLK_RIGHT:
			if (cur_pos < int(command_line.size()))
				cur_pos++;
			break;

		case SDLK_LEFT:
			if (cur_pos > 0)
				cur_pos--;
			break;

		case SDLK_RETURN:
			r = command(command_line);
			command_line = "";
			cur_pos = 0;
			break;

		case SDLK_SPACE:
			command_line.insert(cur_pos, " ");
			cur_pos++;
			break;

		case SDLK_BACKSPACE:
			if (cur_pos > 0)
			{
				command_line.erase(cur_pos - 1, 1);
				cur_pos--;
			}
			break;

		case SDLK_DELETE:
			command_line.erase(cur_pos, 1);

			break;

		default:
			if (cur_pos < ((Engine::screenSettings.screenWidth - 35) / 13))
			{
				command_line += SDL_GetKeyName(key_pressed.key.keysym.sym);
				cur_pos++;
			}

			break;
		}

	}

	return r;
}

void glConsole::show()
{
	glDisable(GL_LIGHTING);
	glEnable(GL_BLEND);
	glDisable(GL_DEPTH_TEST); // Disables Depth Testing
	glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
	glPushMatrix(); // Store The Projection Matrix
	glLoadIdentity(); // Reset The Projection Matrix
	glOrtho(0, Engine::screenSettings.screenWidth, 0,
			Engine::screenSettings.screenHeight, -1, 1); // Set Up An Ortho Screen
	glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
	glPushMatrix(); // Store The Modelview Matrix
	glLoadIdentity(); // Reset The Modelview Matrix
	glTranslated(0, 0, 0); // Position The Text (0,0 - Bottom Left)

	glCallList(background);

	glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
	glPopMatrix(); // Restore The Old Projection Matrix
	glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
	glPopMatrix(); // Restore The Old Projection Matrix
	glEnable(GL_DEPTH_TEST); // Enables Depth Testing
	glEnable(GL_LIGHTING);

	show_lines();

	show_cursor();

	glDisable(GL_BLEND);
}

glConsole::~glConsole()
{
	font->KillFont();
	glDeleteLists(background, 1);
	//dtor
}
